﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using Logic.Mappings;

namespace Logic.Packet
{
    public class CL_MessageOfTheDay : T4CBasePak
    {

        public CL_MessageOfTheDay(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendLine("PAK MessageOfTheDay");

            return sb.ToString();
        }
    }

    public class CL_PlayerMove_N : T4CBasePak
    {

        public CL_PlayerMove_N(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendLine("is moving North.");

            return sb.ToString();
        }

        public void Compute()
        {
            //throw new NotImplementedException();
        }
    }

    public class CL_PlayerMove_NE : T4CBasePak
    {

        public CL_PlayerMove_NE(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is moving North East.");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_PlayerMove_E : T4CBasePak
    {

        public CL_PlayerMove_E(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is moving East.");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_PlayerMove_SE : T4CBasePak
    {

        public CL_PlayerMove_SE(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is moving South East.");
            sb.AppendLine();

            return sb.ToString();
        }
    }


    public class CL_PlayerMove_S : T4CBasePak
    {

        public CL_PlayerMove_S(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is moving South.");
            sb.AppendLine();

            return sb.ToString();
        }
    }


    public class CL_PlayerMove_SW : T4CBasePak
    {

        public CL_PlayerMove_SW(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is moving South West.");
            sb.AppendLine();

            return sb.ToString();
        }
    }


    public class CL_PlayerMove_W : T4CBasePak
    {

        public CL_PlayerMove_W(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is moving West.");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_PlayerMove_NW : T4CBasePak
    {

        public CL_PlayerMove_NW(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is moving North West.");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_PlayerMove_Stop : T4CBasePak
    {

        public CL_PlayerMove_Stop(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("has stopped moving.");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_KeepAlive : T4CBasePak
    {
        public CL_KeepAlive(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Pong !");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_GetObject : T4CBasePak
    {
        /// <summary>
        /// object's X coordinate on map
        /// </summary>
        Int16 XCoord;
        /// <summary>
        /// object's Y coordinate on map
        /// </summary>
        Int16 YCoord;
        /// <summary>
        /// object unit ID
        /// </summary>
        uint ObjectID;
        public CL_GetObject(T4CBasePak pak)
            : base(pak.Data)
        {


        }

        public override string Display()
        {

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is trying to grab item {0} at X : {1} Y : {2} !", ObjectID, XCoord, YCoord);
            sb.AppendLine();

            return sb.ToString();
        }
        public override void ResolveData()
        {
            XCoord = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            ObjectID = BitConverter.ToUInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
        }
    }

    public class CL_Login : T4CBasePak
    {
        public string Login { get; set; }
        public string Password { get; set; }
        public Int16 ClientVersion { get; set; }
        public Int16 Unknown { get; set; }

        public CL_Login(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            byte loginSize = DataPak.Skip(2).Take(1).Single();
            byte passwordSize = DataPak.Skip(3 + loginSize).Take(1).ToArray().Single();

            //Wrong characters displayed sometimes in login/password
            Login = ASCIIEncoding.ASCII.GetString(DataPak.Skip(3).Take(loginSize).ToArray());
            Password = ASCIIEncoding.ASCII.GetString(DataPak.Skip(3 + loginSize + 1).Take(passwordSize).ToArray());
            ClientVersion = BitConverter.ToInt16(DataPak.Skip(3 + loginSize + 1 + passwordSize + 2).Take(2).ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("login : {0} Password :{1}  Version : {2}", Login, Password, ClientVersion);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_PatchServerInformation : T4CBasePak
    {
        public CL_PatchServerInformation(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is asking for server patch information");
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_IndirectTalk : T4CBasePak
    {
        /// <summary>
        /// Player ID in database
        /// </summary>
        public uint UnitId { get; set; }

        /// <summary>
        /// Current orientation (no change == 0)
        /// </summary>
        public byte UnitOrientation { get; set; }

        /// <summary>
        /// Unused? usually 00 00 BE BE
        /// </summary>
        public uint TextColor { get; set; }

        /// <summary>
        /// Message to display
        /// </summary>
        public string Message { get; set; }

        public CL_IndirectTalk(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {

            UnitId = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            UnitOrientation = DataPak.Skip(6).Take(1).Single();
            TextColor = BitConverter.ToUInt32(DataPak.Skip(7).Take(4).Reverse().ToArray(), 0);

            //reverse numeric values
            Int16 messageLength = BitConverter.ToInt16(DataPak.Skip(11).Take(2).Reverse().ToArray(), 0);
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(13).Take(messageLength).ToArray());
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Player (Id:{0}) says {1}", UnitId, Message);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_Shout : T4CBasePak
    {
        /// <summary>
        /// Player name : ignored (corrected by server if wrong)
        /// </summary>
        public string PlayerName { get; set; }

        /// <summary>
        /// Unused
        /// </summary>
        public uint TextColor { get; set; }

        /// <summary>
        /// Message to send
        /// </summary>
        public string Message { get; set; }

        public CL_Shout(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {
            //reverse numeric values
            Int16 playerNameLength = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            Int16 messageLength = BitConverter.ToInt16(DataPak.Skip(4 + playerNameLength + 4).Take(2).Reverse().ToArray(), 0);

            PlayerName = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4).Take(playerNameLength).ToArray());

            TextColor = BitConverter.ToUInt32(DataPak.Skip(4 + playerNameLength).Take(4).Reverse().ToArray(), 0);
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4 + playerNameLength + 6).Take(messageLength).ToArray());
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Player shout {1}", PlayerName, Message);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_ChannelMessage : T4CBasePak
    {
        public string ChannelName { get; set; }
        public string Message { get; set; }

        public CL_ChannelMessage(T4CBasePak pak) : base(pak.Data) { }

        public override void ResolveData()
        {
            //reverse numeric values
            Int16 channelLength = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            Int16 messageLength = BitConverter.ToInt16(DataPak.Skip(4 + channelLength).Take(2).Reverse().ToArray(), 0);

            ChannelName = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4).Take(channelLength).ToArray());
            Message = ASCIIEncoding.ASCII.GetString(DataPak.Skip(4 + channelLength + 2).Take(messageLength).ToArray());
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Channel {0} : {1}", ChannelName, Message);
            sb.AppendLine();

            return sb.ToString();
        }
    }

    public class CL_PersonalSpellList : T4CBasePak
    {
        /// <summary>
        /// 0x01 if god
        /// </summary>
        public byte Unknown { get; set; }

        public CL_PersonalSpellList(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override void ResolveData()
        {
            Unknown = DataPak.Skip(2).Take(1).Single();
        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is requesting spell list with this unknown parameter : {0}", Unknown);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_BackpackItems : T4CBasePak
    {
        public Int16 Unknown { get; set; }

        public CL_BackpackItems(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            Unknown = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is requesting inventory with this unknown parameter : {0}", Unknown);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_EquippedItems : T4CBasePak
    {
        public CL_EquippedItems(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is requesting equipped items.");
            sb.AppendLine();
            return sb.ToString();
        }
    }
    /// <summary>
    /// request to get the skill list in the stats page
    /// </summary>
    public class CL_PersonalSkills : T4CBasePak
    {

        public CL_PersonalSkills(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is requesting the skill list.");
            sb.AppendLine();
            return sb.ToString();
        }
    }
    /// <summary>
    /// request to use a particular skill on a target
    /// </summary>
    public class CL_UseSkill : T4CBasePak
    {
        public ushort SkillID { get; set; }
        /// <summary>
        ///  target's X coordinate
        /// </summary>
        public Int16 TargetXCoord { get; set; }
        /// <summary>
        /// target's Y coordinate
        /// </summary>
        public Int16 TargetYCoord { get; set; }
        /// <summary>
        /// if player, player ID in database
        /// </summary>
        public uint TargetUnitID { get; set; }

        public CL_UseSkill(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override void ResolveData()
        {
            SkillID = BitConverter.ToUInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            TargetXCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            TargetYCoord = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
            TargetUnitID = BitConverter.ToUInt32(DataPak.Skip(8).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is using skill id {0} on target {1} located at X : {2} Y : {3}", SkillID, TargetUnitID, TargetXCoord, TargetYCoord);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    /// <summary>
    /// request to get the stats list (usually to display the stats page)
    /// </summary>
    public class CL_PersonalStats : T4CBasePak
    {
        public CL_PersonalStats(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is requesting the stats list.");
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_ItemName : T4CBasePak
    {
        public uint ItemID { get; set; }

        public CL_ItemName(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            ItemID = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("is requesting item name for id {0}", ItemID);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    class CL_DepositChest : T4CBasePak
    {
        uint ItemID { get; set; }
        uint ItemCount { get; set; }
        public CL_DepositChest(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override void ResolveData()
        {
            ItemID = BitConverter.ToUInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
            ItemCount = BitConverter.ToUInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("deposit {1} item id {0} to the chest.", ItemID, ItemCount);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    class CL_UseObject : T4CBasePak
    {
        public Int16 XCoord { get; set; }
        public Int16 YCoord { get; set; }
        public int ItemUnitID { get; set; }

        public CL_UseObject(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            XCoord = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            ItemUnitID = BitConverter.ToInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Using item {0} at X {1}  Y {2}.", ItemUnitID, XCoord, YCoord);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_EquipObject : T4CBasePak
    {
        public int ItemID { get; set; }

        public CL_EquipObject(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            ItemID = BitConverter.ToInt32(DataPak.Skip(2).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Equiping item {0}.", ItemID);
            sb.AppendLine();
            return sb.ToString();
        }
    }
    public class CL_UnequipObject : T4CBasePak
    {
        public byte EquipmentPosition { get; set; }
        public CL_UnequipObject(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {

            EquipmentPosition = DataPak.Skip(2).Take(1).Select(c => unchecked((byte)c)).Single();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("UnEquiping item at position {0}.", Enum.GetName(typeof(EquipementPosition), EquipmentPosition));
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_ExitGame : T4CBasePak
    {
        public CL_ExitGame(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            base.ResolveData();
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Exiting the game...");
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_CastSpell : T4CBasePak
    {
        public ushort SpellID { get; set; }
        public Int16 XCoord { get; set; }
        public Int16 YCoord { get; set; }
        public uint TargetUnitID { get; set; }

        public CL_CastSpell(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            SpellID = BitConverter.ToUInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            XCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(6).Take(2).Reverse().ToArray(), 0);
            TargetUnitID = BitConverter.ToUInt32(DataPak.Skip(8).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {

            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Casting spell {0} on target {1} at X {2} Y {3}", Enum.GetName(typeof(Spells), SpellID), TargetUnitID, XCoord, YCoord);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_SendPeriphericObjects : T4CBasePak
    {
        /// <summary>
        /// player character's orientation (9: ignore orientation)
        /// </summary>
        public byte PlayerOrientation { get; set; }
        /// <summary>
        ///  player character's X coordinates on map
        /// </summary>
        public Int16 XCoord { get; set; }
        /// <summary>
        /// player character's Y coordinates on map
        /// </summary>
        public Int16 YCoord { get; set; }

        //   2   int8 player_orientation; // player character's orientation (9: ignore orientation)
        //   3   int16 x_coord; // player character's X coordinates on map
        //   5   int16 y_coord; // player character's Y coordinates on map
        public CL_SendPeriphericObjects(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            PlayerOrientation = DataPak.Skip(2).Take(1).Select(c => unchecked((byte)c)).Single();
            XCoord = BitConverter.ToInt16(DataPak.Skip(3).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(5).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Requesting peripheric objects on orientation {0} at X {1} Y {2}", PlayerOrientation, XCoord, YCoord);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_UseItemByAppearance : T4CBasePak
    {
        public ushort ObjectID { get; set; }
        public CL_UseItemByAppearance(T4CBasePak pak)
            : base(pak.Data)
        {

        }
        public override void ResolveData()
        {
            ObjectID = BitConverter.ToUInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Using item :{0}", ObjectID);
            sb.AppendLine();
            return sb.ToString();
        }
    }

    public class CL_Attack : T4CBasePak
    {
        //   2   int16 x_coord;
        //   4   int16 y_coord;
        //   6   int32 unit_id;

        /// <summary>
        ///  player character's X coordinates on map
        /// </summary>
        public Int16 XCoord { get; set; }
        /// <summary>
        /// player character's Y coordinates on map
        /// </summary>
        public Int16 YCoord { get; set; }

        public uint TargetUnitID { get; set; }


        public CL_Attack(T4CBasePak pak)
            : base(pak.Data)
        {

        }

        public override void ResolveData()
        {
            XCoord = BitConverter.ToInt16(DataPak.Skip(2).Take(2).Reverse().ToArray(), 0);
            YCoord = BitConverter.ToInt16(DataPak.Skip(4).Take(2).Reverse().ToArray(), 0);
            TargetUnitID = BitConverter.ToUInt32(DataPak.Skip(6).Take(4).Reverse().ToArray(), 0);
        }
        public override string Display()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine(base.Display());
            sb.AppendFormat("Attacking {0} at X {1} Y {2}", TargetUnitID, XCoord, YCoord);
            sb.AppendLine();
            return sb.ToString();
        }
    }
}
